/*
 * @Author: fhw
 * @Date: 2022-07-08 15:02:07
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2023-02-04 22:10:26
 * @Description:
 */
import { computed, defineComponent, onDeactivated, onMounted, reactive, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import {
	ArrowLeftOutlined,
	ArrowRightOutlined,
	CalendarOutlined,
	CommentOutlined,
	UserOutlined,
	CaretRightFilled,
	FolderOpenOutlined,
	EyeOutlined,
	BarsOutlined,
	LikeOutlined,
	LikeFilled,
	MessageOutlined,
	RightOutlined,
	ArrowUpOutlined,
} from '@ant-design/icons-vue'
import '../style.scss'
import ThumbsUp from '@/components/thumbsUp'
import { clone, equals, isEmpty, isNil, map } from 'ramda'
import { isTrue, throttle } from '@/utils/tools'
import { ArticleModule } from '@/store/modules/articleData'
import { notification } from 'ant-design-vue'
import dayjs from 'dayjs'
import { formatTime } from '@/utils'
import '../style.scss'
import { FormTextArea } from '@/components'
import { BasicDataModule } from '@/store/modules/basicData'
import { Article, Comment } from '@/interface'
import { PrevNext } from './interface'
interface CommentState extends Comment {
	/** 是否显示点赞数 */
	showLike?: boolean
	/** 是否显示回复 */
	showReply?: boolean
	/** 评论内容 */
	replyContent?: string
	/** 二级页数 */
	pageSize?: number
}
interface PageState {
	data?: Article
	prev?: PrevNext
	next?: PrevNext
}
function toScrollTop() {
	setTimeout(() => {
		const message = document.querySelector('.details article') as HTMLElement
		if (!message) return
		message.scrollTop = 0
	}, 10)
}
export default defineComponent({
	name: 'ArticleDetails',
	setup() {
		const articleLikes = ref<number[]>(JSON.parse(localStorage.getItem('articleLikes') ?? '[]'))
		const articleRead = ref<number[]>(JSON.parse(localStorage.getItem('articleReadId') ?? '[]'))
		const commentLike = ref<number[]>(JSON.parse((localStorage.getItem('commentLike') as string) ?? '[]'))
		const preview = ref()
		const hearted = computed(() => {
			return articleLikes.value.includes(pageState.value.data?.id as number)
		})
		const articleLately = computed(() => {
			return ArticleModule.articleLately
		})
		const articleHot = computed(() => {
			return ArticleModule.articleHot
		})
		onMounted(() => {
			if (isEmpty(ArticleModule.articleLately)) {
				ArticleModule.getArticleLately()
			}
			if (isEmpty(ArticleModule.articleHot)) {
				ArticleModule.getArticleHot()
			}
			// 获取用户详情
			if (!isTrue(BasicDataModule.userInfo)) {
				BasicDataModule.getUserInfo()
			}
		})
		const userInfo = computed(() => {
			return clone(BasicDataModule.userInfo)
		})
		const titles = ref<any[]>([])
		const route = useRoute()
		const router = useRouter()
		const loading = ref(false)
		const pageState = ref<PageState>({})
		async function getArticleInfo() {
			if (loading.value || isNil(route.params.id)) return
			loading.value = true
			const { success, data } = await API.blog.article.getArticleInfo.request({ id: route.params.id })
			if (success) {
				loading.value = false
				pageState.value.data = data.data
				pageState.value.prev = data.prev
				pageState.value.next = data.next
				!articleRead.value.includes(Number(route.params.id)) && updateArticleReadCount()
				// 延时执行，等待数据渲染完
				setTimeout(() => {
					const anchors = preview.value.$el.querySelectorAll('h1,h2,h3,h4,h5,h6')
					const titlesTrim = Array.from(anchors).filter((title: any) => !!title.innerText.trim())
					if (!titlesTrim.length) {
						titles.value = []
						return
					}
					const hTags = Array.from(new Set(titlesTrim.map((title: any) => title.tagName))).sort()
					titles.value = titlesTrim.map((el: any) => ({
						title: el.innerText,
						lineIndex: el.getAttribute('data-v-md-line'),
						indent: hTags.indexOf(el.tagName),
					}))
					setTimeout(() => {
						// 获取吸顶元素的dom
						// 吸顶元素到top的距离
						catalogueState.offsetTop = catalogue.value.offsetTop
						// 元素自身的高度
						catalogueState.offsetHeight = catalogue.value.offsetHeight
						// 监听滚动条
						window.addEventListener('scroll', handleScroll)
					}, 500)
				}, 100)
			}
		}
		// 目录是否吸顶
		const catalogue = ref<any>()
		const catalogueState = reactive({
			offsetTop: 0,
			offsetHeight: 0,
			headerFixed: false,
		})
		function handleScroll() {
			// 得到页面滚动的距离，兼容写法
			const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
			// 判断页面滚动的距离是否大于吸顶元素的位置
			catalogueState.headerFixed = scrollTop > catalogueState.offsetTop - catalogueState.offsetHeight
		}
		onDeactivated(() => {
			window.removeEventListener('scroll', handleScroll)
		})
		// 目录锚点
		function handleAnchorClick(anchor: { lineIndex: any }) {
			const { lineIndex } = anchor
			const heading = preview.value.$el.querySelector(`[data-v-md-line="${lineIndex}"]`)
			if (heading) {
				preview.value.scrollToTarget({
					target: heading,
					scrollContainer: document.querySelector('.details article'),
					top: 100,
				})
			}
		}
		// 更新阅读数
		async function updateArticleReadCount() {
			const { success } = await API.blog.article.updateArticleReadCount.request({ id: route.params.id })
			if (success) {
				if (pageState.value.data?.read) {
					;(pageState.value.data.read as number) += 1
				}
				localStorage.setItem('articleReadId', JSON.stringify(articleRead.value.concat([Number(route.params.id)])))
			}
		}
		function toBlog(id: number | undefined) {
			if (isNil(id) || equals(Number(route.params.id), id)) return
			commentState.value.data = []
			toScrollTop()
			router.push({
				path: `/articleDetails/${id}`,
			})
		}
		const onThumbsUp = throttle(async function (type: boolean) {
			let storageValue: number[] = []
			if (isNil(pageState.value.data?.id) || hearted.value) return
			if (type) {
				storageValue = [...articleLikes.value, pageState.value.data?.id as number]
			}
			const { success } = await API.blog.article.updateArticleThumbsUp.request({ id: route.params.id })
			if (success) {
				localStorage.setItem('articleLikes', JSON.stringify(storageValue))
			}
			!isNil(pageState.value.data?.thumbUp) && (((pageState.value.data as Article).thumbUp as number) += 1)
			articleLikes.value = clone(storageValue)
		})
		const commentState = ref({
			data: [] as CommentState[],
			loading: false,
			pageState: {},
		})

		const pagination = reactive({
			pageNum: 1,
			pageSize: 10,
			total: 0,
		})
		// 分页事件
		function onChange(pageNum: number, pageSize: number) {
			pagination.pageNum = pageNum
			pagination.pageSize = pageSize
			getArticleComment()
		}
		watch(
			() => route,
			() => {
				pageState.value = {
					data: undefined,
					prev: undefined,
					next: undefined,
				}
				getArticleInfo()
				getArticleComment()
			},
			{
				immediate: true,
				deep: true,
			}
		)

		// 获取评论
		async function getArticleComment() {
			if (isNil(route.params.id)) return
			const { pageNum, pageSize } = pagination
			commentState.value.loading = true
			const { success, data } = await API.blog.articleComment.getComment.request({
				articleId: route.params.id,
				pageNum,
				pageSize,
			})
			commentState.value.loading = false
			if (success) {
				pagination.pageNum = data.pageNum
				pagination.pageSize = data.pageSize
				pagination.total = data.total
				commentState.value.data = data.data.map((item: CommentState) => {
					item.replys?.forEach((val: any) => {
						if (commentLike.value.includes(val.id as number)) {
							val.showLike = true
						}
					})
					item.pageSize = 2
					return {
						...item,
						showReply: false,
						showLike: commentLike.value.includes(item.id as number),
					}
				})
			}
		}
		const userState = ref({
			name: null,
			content: '',
			email: '',
		})
		/**
		 * 发表评论
		 * @param data 二层评论
		 * @returns 外层评论无需传用户id名称，二级需要
		 */
		async function onCommentSend(data?: CommentState) {
			const params: API.blog.articleComment.comment.Params = {
				articleId: pageState.value.data?.id,
				content: data?.replyContent ?? userState.value.content,
				commentId: data?.id,
				userId: userInfo.value.id,
				toUserId: null,
			}
			console.log(data)

			// 二级评论回复
			if (!isNil(data?.id)) {
				params.toUserId = data?.userId
			}
			commentState.value.loading = true
			const { success } = await API.blog.articleComment.comment.request(params)
			commentState.value.loading = false
			if (success) {
				notification.success({
					message: '提示',
					description: '评论成功',
				})
				userState.value.content = ''
				commentState.value.data = []
				getArticleComment()
			}
		}
		/** 更新评论点赞数 */
		async function updateCommentLikes(record: CommentState) {
			let storageValue: number[] = []
			if (record.showLike) {
				const index = commentLike.value.findIndex((item) => equals(item, record.id))
				commentLike.value.splice(index, 1)
				storageValue = clone(commentLike.value)
			} else {
				storageValue = [...commentLike.value, record.id as number]
			}
			const { success } = await API.blog.articleComment.updateCommentLikes.request({
				id: record.id,
				content: record.content,
				userId: record.userId,
			})
			if (success) {
				localStorage.setItem('commentLike', JSON.stringify(storageValue))
			}
			!isNil(record.like_num) && record.showLike ? (record.like_num -= 1) : ((record.like_num as number) += 1)
			record.showLike = !record.showLike
			commentLike.value = clone(storageValue)
		}
		/** 点赞、回复工具栏 */
		function actionRender(record: CommentState) {
			return (
				<div>
					<span
						class="comment-like"
						style={{ color: record.showLike ? '#1e80ff' : '', fontSize: '14px', cursor: 'pointer' }}
						onClick={() => updateCommentLikes(record)}
					>
						{record.showLike ? <LikeFilled /> : <LikeOutlined />}
						{isNil(record.like_num) || equals(record.like_num, 0) ? ' 点赞' : ` ${record.like_num}`}
					</span>
					<span
						key="comment-nested-reply-to"
						class="comment-nested-reply-to"
						style={{ color: record.showReply ? '#1e80ff' : '' }}
						onClick={() => (record.showReply = !record.showReply)}
					>
						{record.showReply ? (
							'取消回复'
						) : (
							<span>
								<MessageOutlined style="margin-right:4px;font-size:14px" />
								{record.replys?.length || '回复'}
							</span>
						)}
					</span>
				</div>
			)
		}
		/** 二级评论 */
		function authorRender(record: CommentState) {
			return (
				<a>
					{record.user?.username}
					{!isNil(record.toUserId) && (
						<>
							<CaretRightFilled style="margin:0 10px" />
							<span>{record.toUser?.username}</span>
						</>
					)}
				</a>
			)
		}
		/** 头像 */
		function avatarRender() {
			return <a-avatar v-slots={{ icon: () => <UserOutlined /> }} />
		}
		/** 一级评论 */
		function contentRender(record: CommentState) {
			return (
				<div>
					<p v-html={record.content}></p>
					<span style="color: rgb(153, 153, 153);margin-top:5px">{dayjs(record.createDate).format('MM-DD')}</span>
				</div>
			)
		}
		return () => (
			<div class="conWidth details">
				<aside>
					<header>
						<ArrowLeftOutlined
							style="font-size: 22px;cursor: pointer;"
							onClick={() => {
								router.push('/article')
							}}
						/>
					</header>
					<div>
						<h3>热门</h3>
						<ul>
							{map(
								(item) => (
									<li
										onClick={() => {
											toBlog(item.value as number)
										}}
										class={`${equals(route.params.id, String(item.value)) ? 'active' : ''} one-hidden`}
									>
										{item.label} {item.id}
									</li>
								),
								articleHot.value
							)}
						</ul>
						{isEmpty(articleHot.value) && (
							<div style="text-align: center;margin: 10px auto ;padding:10px 0">
								<a-empty />
							</div>
						)}
					</div>
					<div>
						<h3>最新文章</h3>
						<ul>
							{map(
								(item) => (
									<li
										onClick={() => {
											toBlog(item.value as number)
										}}
										class={`${equals(route.params.id, String(item.value)) ? 'active' : ''} one-hidden`}
									>
										{item.label}
									</li>
								),
								articleLately.value
							)}
						</ul>
						{isEmpty(articleLately.value) && (
							<div style="text-align: center;margin: 10px auto ;padding:10px 0">
								<a-empty />
							</div>
						)}
					</div>
					{!isEmpty(titles.value) && (
						<div class={catalogueState.headerFixed ? 'issFixed' : ''} ref={catalogue}>
							<h3>目录</h3>
							<ul>
								{map(
									(item) => (
										<li class="one-hidden" onClick={() => handleAnchorClick(item)}>
											{item.title}
										</li>
									),
									titles.value
								)}
							</ul>
						</div>
					)}
				</aside>
				<article>
					<div>
						{loading.value && (
							<div class="skeleton">
								<a-skeleton active />
								<a-skeleton active />
								<a-skeleton active />
							</div>
						)}
						<h1>{pageState.value.data?.title}</h1>
						<div class="article-message">
							<div class="date">
								<CalendarOutlined />
								{formatTime(pageState.value.data?.createDate as string)}
							</div>
							<div class="comment">
								<CommentOutlined />
								{commentState.value.data.length}条评论
							</div>
							<div class="username">
								<UserOutlined />
								发布者：<span>{pageState.value.data?.user?.username}</span>
							</div>
							<div class="tags">
								<FolderOpenOutlined />
								{pageState.value.data?.tags?.join('，')}
							</div>
							<div class="category flexBox">
								<EyeOutlined />
								<span>{pageState.value.data?.read}</span>
							</div>
							<div class="category">
								<BarsOutlined />
								{pageState.value.data?.category}
							</div>
						</div>
						{!isEmpty(pageState.value.data?.imageUrl) && (
							<div style="text-align: center;">
								<img src={pageState.value.data?.imageUrl} alt="" style="width: 100%" />
							</div>
						)}
						{pageState.value.data && (
							<v-md-preview v-model={[pageState.value.data.content, 'text']} ref={preview}></v-md-preview>
						)}
						<div class="fabulous">
							<ThumbsUp onThumbsUp={onThumbsUp} hearted={hearted.value} count={pageState.value.data?.thumbUp} />
						</div>
						<a-divider />
						<div class="prevNext-box j_b_box">
							<div style={!pageState.value.prev?.title ? 'color: #91A2B4' : ''}>
								<a-tooltip
									v-slots={{ title: () => pageState.value.prev?.title ?? '暂无文章' }}
									onClick={() => {
										toBlog(pageState.value.prev?.id)
									}}
								>
									<ArrowLeftOutlined />
									上一篇
								</a-tooltip>
							</div>
							<div style={!pageState.value.next?.title ? 'color: #91A2B4' : ''}>
								<a-tooltip
									v-slots={{ title: () => pageState.value.next?.title ?? '暂无文章' }}
									onClick={() => {
										toBlog(pageState.value.next?.id)
									}}
								>
									下一篇
									<ArrowRightOutlined />
								</a-tooltip>
							</div>
						</div>
					</div>
					<div class="comment">
						<div style="width: 50%;padding: 20px 0;margin: 0 auto">
							<FormTextArea
								showEmotion
								onSend={() => {
									onCommentSend()
								}}
								v-model={[userState.value.content, 'content']}
							/>
						</div>
						<div>
							{commentState.value.loading && (
								<div class="skeleton" style="padding:10px 0">
									<a-skeleton active />
								</div>
							)}
							{!commentState.value.loading && isEmpty(commentState.value.data) && (
								<div style="text-align: center;margin: 100px auto ; padding-bottom:100px">
									<a-empty description="暂无评论" />
								</div>
							)}
							{map((item: CommentState) => {
								return (
									<a-comment
										v-slots={{
											actions: () => actionRender(item),
											author: () => authorRender(item),
											avatar: () => avatarRender(),
											content: () => contentRender(item),
										}}
									>
										{item.showReply && (
											<div style="width:50%">
												<FormTextArea
													showEmotion
													onSend={() => {
														onCommentSend({
															...item,
															replyContent: item.replyContent,
														})
													}}
													v-model={[item.replyContent, 'content']}
												/>
											</div>
										)}
										{!isNil(item.replys) && !isEmpty(item.replys) && (
											<div style="background: rgba(247,248,250,.7);padding: 20px;">
												{map((val) => {
													return (
														<>
															<a-comment
																v-slots={{
																	actions: () => actionRender(val),
																	author: () => authorRender(val),
																	avatar: () => avatarRender(),
																	content: () => contentRender(val),
																}}
															>
																{val.showReply && (
																	<div style="width:50%">
																		<FormTextArea
																			showEmotion
																			onSend={() => {
																				onCommentSend({
																					...val,
																					id: item.id,
																					replyContent: item.replyContent,
																				})
																			}}
																			v-model={[item.replyContent, 'content']}
																		/>
																	</div>
																)}
															</a-comment>
														</>
													)
												}, item.replys?.slice(0, item.pageSize) ?? [])}
												{(item.pageSize as number) < item.replys?.length && (
													<a-button
														class="openBtn"
														onClick={() => {
															item.pageSize = item.replys?.length
														}}
													>
														展开其他 {item.replys?.length - (item.pageSize as number) ?? 0} 条回复 <RightOutlined />
													</a-button>
												)}
											</div>
										)}
									</a-comment>
								)
							}, commentState.value.data)}
						</div>
						{!commentState.value.loading && !isEmpty(commentState.value.data) && (
							<div class="pagination">
								<a-pagination
									show-quick-jumper
									v-models={[
										[pagination.pageNum, 'current1'],
										[pagination.pageSize, 'pageSize'],
									]}
									total={pagination.total}
									onChange={onChange}
								/>
							</div>
						)}
					</div>
				</article>

				<a-backTop>
					<ArrowUpOutlined />
				</a-backTop>
			</div>
		)
	},
})
